﻿using System;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading;
using System.IO;
using System.Diagnostics;

namespace UnionnetClient.Model
{
	public class LoginHelper
	{
		#region 公有成员

		public event EventHandler LoginCompleted;
		public event EventHandler LoginTimeout;

		internal LoginStateType LoginState //登陆状态
		{
			get 
			{
				//if (loginThread != null && loginThread.IsAlive)
				//{
				//    return LoginStateType.Logining;
				//}
				//else
				//{
				return loginState;
				//}
			}
		}

		/// <summary>
		/// 获取自主服务地址
		/// </summary>
		public string ServiceAddress
		{
			get { return serviceAddress == null ? string.Empty : serviceAddress; }
		}

		/// <summary>
		/// 当发生异常时， 通过该属性获得异常消息
		/// </summary>
		public string ExceptionMessage
		{
			get { return exceptionMessage; }
		}
	
		internal void LoginAsync(LoginData ld)
		{
			this.loginState = LoginStateType.Logining;
			loginTimer = new Timer(OnTimeout, null, ld.LoginTimeout, 0); //timeout毫秒后执行OnTimeout()，且只执行一次
			loginThread = new Thread(LoginLoop);
			loginThread.Name = "Login Thread";
			//Debug.WriteLine("Login Start.");
			//Debug.WriteLine("PostAddress : " + ld.PostAddress);
			//Debug.WriteLine("PostParameters : " + ld.PostParameters);
			loginThread.Start(new LoginParameter(ld.PostAddress, ld.PostParameters, ld.LoginAttemptInterval));
		}

		public void CancelLogin()
		{
			CancelLogin(false);
		}

		public bool Logout()
		{
			if (timerHtmlContent.Length > 0)
			{
				Roovent.HttpOperator.HtmlForm timerform = Roovent.HttpOperator.FormParser.ParseForm(timerHtmlContent);
				timerform.Labels["act"].Attributes["value"] = "logout";
				string logout_html = Roovent.HttpOperator.HttpTransfer.SubmitForm(timerform);

				if (logout_html.Contains("注销成功"))
				{
					return true;
				}
				else
				{
					AppLog.ErrorLog("注销失败");
					AppLog.InfoLog(logout_html);
				}
			}
			return false;
		}

		#endregion

		#region 私有

		private Timer loginTimer; //控制登陆超时
		private Thread loginThread;
		private object objLock = new object(); //用于同步值类型(loginState)

		private LoginStateType loginState = LoginStateType.NoLogin;
		private string exceptionMessage;
		private string serviceAddress;

		private string timerHtmlContent;

		private LoginStateType LoginOnce(string postAddress, string postParameters,out string authHtml)
		{
			LoginStateType r;// = LoginStateType.Failed;
			string authHtmlContent;

			try
			{
				authHtmlContent = Roovent.HttpOperator.HttpTransfer.SubmitForm(postAddress, postParameters);
			}
			catch (WebException ex)
			{
				throw ex;
			}
			finally
			{
			}

			if (authHtmlContent.Contains("密码"))
			{
				r = LoginStateType.PasswordWrong;
			}
			else if (authHtmlContent.Contains("重复登入"))
			{
				r = LoginStateType.Repetition;
			}
			else if (authHtmlContent.Contains("登入失败"))
			{
				r = LoginStateType.Failed;
			}
			else if (authHtmlContent.Contains("认证成功"))
			{
				r = LoginStateType.Successful;
			}
			else
			{
				r = LoginStateType.Unknown;
				this.exceptionMessage = authHtmlContent;
			}

			authHtml = authHtmlContent;
			//System.Diagnostics.Debug.WriteLine(authHtmlContent);
			return r;
		}

		private void LoginLoop(object loginParameter)
		{
			LoginParameter lp = loginParameter as LoginParameter;
			LoginStateType state = LoginStateType.Failed;
			string authHtmlContent = string.Empty;

			int count = 1; //登陆次数

			try
			{
				state = LoginOnce(lp.PostAddress, lp.PostParemeters,out authHtmlContent);
				while (state == LoginStateType.Failed)
				{		
					Thread.Sleep(lp.Interval);
					AppLog.EventLog(string.Format("登陆失败 {0}", ++count));
					Debug.WriteLine(string.Format("登陆失败 {0}", count));
					Debug.WriteLine(authHtmlContent);
					state = LoginOnce(lp.PostAddress, lp.PostParemeters, out authHtmlContent);
				}
			}
			catch (WebException ex)
			{
				state = LoginStateType.Execption;
				exceptionMessage = ex.Message;
			}
			finally
			{
			}

			lock (objLock)
			{
				loginState = state;
			}

			if (loginState == LoginStateType.Successful)
			{
				serviceAddress = GetServiceAddress(authHtmlContent);
				Debug.WriteLine("!!!!!!!!!" + authHtmlContent);
				ThreadPool.QueueUserWorkItem(VisitTimerPage,authHtmlContent);
			}

			OnLoginCompleted();
		}

		private void OnTimeout(object o)
		{
			CancelLogin(true);
		}

		private void OnLoginCompleted()
		{
			if (LoginCompleted != null)
			{
				AppLog.EventLog(string.Format("登陆完成 {0}", LoginState.ToString()));
				LoginCompleted(null, EventArgs.Empty);
			}
		}

		/// <summary>
		/// 取消登陆。当没有在登陆时不会抛出异常。
		/// </summary>
		/// <param name="timeout">是否因为超时而取消</param>
		private void CancelLogin(bool timeout) 
		{
			if (loginTimer != null)
			{
				loginTimer.Dispose();
				System.Diagnostics.Debug.WriteLine(
					string.Format("loginTimer Disposed. loginTimer {0} null.",loginTimer == null ? "==" : "!="));
				//loginTimer = null;
			}

			if (loginThread != null && loginThread.IsAlive)
			{
				loginThread.Abort();
				System.Diagnostics.Debug.WriteLine(
					string.Format("loginThread aborted. IsAlive : {0}; ThreadState : {1}", loginThread.IsAlive,loginThread.ThreadState));

				if (timeout)
				{
					lock (objLock)
					{
						loginState = LoginStateType.Timeout;
					}
					if (LoginTimeout != null)
					{
						LoginTimeout(null, EventArgs.Empty);
					}
				}
				else
				{
					lock (objLock)
					{
						loginState = LoginStateType.Canceled;
					}
				}

				loginThread.Join(); //确保登陆线程终止
				System.Diagnostics.Debug.WriteLine(
					string.Format("loginThread's ThreadState : {0}", loginThread.ThreadState));
			}
		}

		/// <summary>
		/// 获取自助服务地址
		/// </summary>
		private string GetServiceAddress(string authHtmlContent) 
		{
			Match m = Regex.Match(
				authHtmlContent,
				"replace\\(\\s*[\"\']?\\s*(http:\\/\\/[\\w\\.\\?\\/=&]*)\\s*[\"\']?\\s*\\)",
				RegexOptions.IgnoreCase);

			if (m.Length > 0)
			{
				return m.Groups[1].Value;
			}
			else
			{
				return string.Empty;
			}
		}

		private string GetTimerAddress(string authHtmlContent) //获取timer页面地址
		{
			Match m1 = Regex.Match(authHtmlContent, "<form.*?action=[\"\']?(.+)[\"\']?.*?>", RegexOptions.IgnoreCase);
			string rootAddr = m1.Groups[1].Value;
			rootAddr = rootAddr.Substring(0, rootAddr.LastIndexOf('/') + 1);
			Match m2 = Regex.Match(authHtmlContent, "splashWin\\.location\\s*=\\s*[\"\'](.*?)[\"\']", RegexOptions.IgnoreCase);
			string relativeAddr = m2.Groups[1].Value;
			return rootAddr + relativeAddr;
		}

		private void VisitTimerPage(object o)
		{
			string authHtmlContent = o as string;
			WebClient wc = new WebClient();
			//lock (objLock)
			//{
				timerHtmlContent = wc.DownloadString(GetTimerAddress(authHtmlContent));
			//}
		}
		#endregion
	}
}
